package com.auz.datagenerator.connector;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import javax.swing.JPanel;

import com.auz.datagenerator.connector.heuristiclink.ValueHeuristicLink;
import com.auz.datagenerator.guiconnector.AbstractPreviewOptionPanel;
import com.auz.datagenerator.guiconnector.GUIConnector;
import com.auz.datagenerator.guiconnector.PreviewOptionPanel;
import com.auz.datagenerator.heuristics.time.IIntervalHeuristic;
import com.auz.datagenerator.publishing.IPublisher;

/**
 * Core class linking the components together. This class is abstract and provides the 
 * basis for the standard expected behaviour of the system.
 * @author Aurelien Bonnel
 */
public class AbstractConnector extends Thread implements IConnector {

	Logger logger = Logger.getLogger("AbstractConnector");

	// TODO: change the publisher to allow other than double types
	List<IIntervalHeuristic> timers;
	List<IPublisher> publishers;
	List<ValueHeuristicLink> valueHeuristicLinks;

	private AbstractPreviewOptionPanel preview;

	private TypeHandler handler;

	/**
	 * Constructor
	 * @param _timer - an interval heuristic
	 * @param _valueHeuristiclink - a value heuristic
	 * @param _publisher - a publishing heuristic
	 * @param _handler - a type handler
	 */
	public AbstractConnector(IIntervalHeuristic _timer, ValueHeuristicLink _valueHeuristiclink, IPublisher<Double> _publisher, TypeHandler _handler) {
		timers = new ArrayList<IIntervalHeuristic>();
		publishers = new ArrayList<IPublisher>();
		valueHeuristicLinks = new ArrayList<ValueHeuristicLink>();

		_timer.setConnector(this);
		timers.add(_timer);
		publishers.add(_publisher);
		valueHeuristicLinks.add(_valueHeuristiclink);
		handler = _handler;
	}

	/**
	 * Adds an interval heuristic to the list of heuristics
	 * @param _interval - the interval heuristic to add
	 */
	public void addIntervalHeuristic(IIntervalHeuristic _interval) {
		timers.add(_interval);
	}

	/**
	 * Adds a publishing heuristic to the list of heuristics
	 * @param _publisher - the publisher heuristic to add
	 */
	public void addPublisher(IPublisher _publisher) {
		publishers.add(_publisher);
	}

	/**
	 * Adds a value heuristic to the list of heuristics
	 * @param _value - the value heuristic to add
	 */
	public void addValueHeuristic(ValueHeuristicLink _value) {
		valueHeuristicLinks.add(_value);
	}

	/**
	 * Removes an interval heuristic to the list of heuristics
	 * @param _interval - the interval heuristic to remove
	 */
	public boolean removeIntervalHeuristic(IIntervalHeuristic _interval) {
		return timers.remove(_interval);
	}

	/**
	 * Removes a publishing heuristic to the list of heuristics
	 * @param _publisher - the publisher heuristic to remove
	 */
	public boolean removePublisher(IPublisher _publisher) {
		return publishers.remove(_publisher);
	}

	/**
	 * Removes a value heuristic to the list of heuristics
	 * @param _value - the value heuristic to remove
	 */
	public boolean removeValueHeuristic(ValueHeuristicLink _value) {
		return valueHeuristicLinks.remove(_value);
	}

	/**
	 * Runs the connecting thread, sequentially launching the GUI, the value heuristics,
	 * the interval heuristics and the publishing heuristics.
	 */
	public void run() {
		GUIConnector connector = new GUIConnector();
		for(ValueHeuristicLink current : valueHeuristicLinks) {
			connector.addPanel(current.fetchGUIComponent());
		}
		for(IIntervalHeuristic current : timers) {
			connector.addPanel(current.fetchGUIComponent());
		}
		// Adds the preview option tick box
		preview = handler.getOutputPanel();
		if(preview != null) {
			connector.addPanel(preview);
		}
		connector.run();
		for(IPublisher current : publishers) {
			new Thread((Runnable) current).start();
		}
		for(IIntervalHeuristic current : timers) {
			current.run();
		}
	}

	/**
	 * Triggers the computation of the value heuristics and the generated value to the publishers
	 */
	public void trigger() {
		logger.info("Connector " + this.hashCode() + " received trigger");
		Object x = new Object();
		for(ValueHeuristicLink current : valueHeuristicLinks) {
			x = current.compute();
			preview.addValue(x);
		}
		for(IPublisher current : publishers) {
			current.publish(x);
		}
	}

}
